import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class LoadTest {

    public static class Client {

        private String host;
        private static final int PORT = 8080;

        public Client(String host) {
            this.host = host;
        }

        public String get(String uri) throws IOException {
            String request
                    = String.format("GET %s HTTP/1.0\r\nHost: %s\r\n", uri, host);
            return makeRequest(request);
        }

        private String makeRequest(String request) throws IOException {
            Socket socket = new Socket(host, PORT);

            final PrintStream printStream
                    = new PrintStream(socket.getOutputStream(), true);
            final Scanner scanner = new Scanner(socket.getInputStream());

            printStream.print(request);

            StringBuilder stringBuilder = new StringBuilder();
            while (scanner.hasNext()) {
                stringBuilder.append(scanner.nextLine());
                stringBuilder.append("\r\n");
            }

            scanner.close();
            socket.close();

            return stringBuilder.toString();
        }
    }


    public static List<Double> runTest(int nClients, int nRequests) throws Exception {
		ExecutorService pool = Executors.newFixedThreadPool(nClients);
		List<Future<Long>> futureStats = new ArrayList<Future<Long>>(nRequests);
		
		for (int i = 0; i < nRequests; i++) {
			Future<Long> future = pool.submit(new Callable<Long>() {

				@Override
				public Long call() throws Exception {
					Client client = new Client("localhost");
					
					long time = System.nanoTime();
					client.get("/");
					time -= System.nanoTime();
					
					return -time;
				}
			});
			
			futureStats.add(future);
		}
		
		pool.shutdown();
		
		List<Double> stats = new ArrayList<Double>(nRequests);
		for (Future<Long> future : futureStats) {
			double timeMillis = 1.0 * future.get() / 1000000;
			stats.add(timeMillis);
		}
		
		return stats;
	}
	
	public static void main(String[] args) throws Exception {
        List<Double> stats = runTest(100,200);
        System.out.println("min: " + Collections.min(stats));
        System.out.println("max: " + Collections.max(stats));
        System.out.println(stats);
	}
}
